package pl.edu.pw.MidEmu.UI.Controllers;

import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JMenuItem;

import pl.edu.pw.MidEmu.Base.Controllers.BaseController;
import pl.edu.pw.MidEmu.Common.Consts;
import pl.edu.pw.MidEmu.Common.Models.CBRDModel;
import pl.edu.pw.MidEmu.Common.Models.MidasModel;
import pl.edu.pw.MidEmu.Logic.ProcessHandler;
import pl.edu.pw.MidEmu.Sensing.Processing.ProcessingAlgorithmServer;
import pl.edu.pw.MidEmu.Sensing.Sensors.ASensor;
import pl.edu.pw.MidEmu.UI.Views.MidasComponentView;

/**
 * Controller for creating new virtual nodes
 * @author Mateusz Starodab
 *
 */
public class MidasComponentController extends BaseController<MidasComponentView> implements MouseListener, MouseMotionListener, ActionListener
{
	/**
	 * @uml.property  name="applications"
	 */
	private List<ProcessHandler> applications;

	private CBRDModel cbrdModel;

	private ProcessHandler cbrdProcessHandler;
	private boolean isDrag = false;

	private MidasModel midasModel;
	private ProcessHandler midasProcessHandler;

	private Point previousPoint = null;

	/**
	 * @uml.property  name="sensors"
	 */
	private List<ASensor> sensors;

	private ProcessingAlgorithmServer sensorsServer;

	public MidasComponentController()
	{
		applications = new ArrayList<ProcessHandler>();
		sensors = new ArrayList<ASensor>();
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource() instanceof JMenuItem)
		{
			JMenuItem source = (JMenuItem) e.getSource();
			if (source.getName() == Consts.MidasComponent_StartMidas)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showStartMidasFrame(point);
			}
			if (source.getName() == Consts.MidasComponent_StopMidas)
			{

				terminate();
				midasProcessHandler = null;
				midasModel = null;
				getView().changeMenusForMidas(false);
			}
			if (source.getName() == Consts.MidasComponent_StartCBRD)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showStartCBRDFrame(point);
			}
			if (source.getName() == Consts.MidasComponent_StopCBRD)
			{
				cbrdProcessHandler.terminate();
				cbrdProcessHandler = null;
				cbrdModel = null;

				getView().changeMenusForCBRD(false);
			}
			if (source.getName() == Consts.MidasComponent_LoadAppMenu)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showClasLoadingFrame(point);
			}
			else if (source.getName() == Consts.MidasComponent_ShowApps)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showRunningApplications(point);
			}
			else if (source.getName() == Consts.MidasComponent_ShowOutput)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showOutputWindow(point);
			}
			else if (source.getName() == Consts.MidasComponent_AddSensor)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showAddSensorWindow(point);
			}
			else if (source.getName() == Consts.MidasComponent_ShowSensors)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showShowSensorWindow(point);
			}
			else if (source.getName() == Consts.MidasComponent_RemoveComponent)
			{
				terminate();
				getView().dispose();
			}
		}
	}

	public void addApplication(ProcessHandler processHandler)
	{
		applications.add(processHandler);
		getView().enableMenuItems();
	}

	public void addSensor(ASensor sensor)
	{
		sensors.add(sensor);
		sensorsServer.registerSensor(sensor);
		sensor.startProcessing();
		getView().enableSensorMenuItems();
		getView().drawSensors();
	}

	/**
	 * @return
	 * @uml.property  name="applications"
	 */
	public List<ProcessHandler> getApplications()
	{
		return applications;
	}

	public CBRDModel getCBRD()
	{
		return cbrdModel;
	}

	public MidasModel getMidas()
	{
		return midasModel;
	}

	public ProcessHandler getMidasHandler()
	{
		return midasProcessHandler;
	}

	/**
	 * @return
	 * @uml.property  name="sensors"
	 */
	public List<ASensor> getSensors()
	{
		return sensors;
	}

	public ProcessingAlgorithmServer getSensorServer()
	{
		return sensorsServer;
	}

	public boolean isCBRDRunning()
	{
		if (cbrdProcessHandler != null)
			return cbrdProcessHandler.isActive();
		else
			return false;
	}

	public boolean isMidasRunning()
	{
		if (midasProcessHandler != null)
			return midasProcessHandler.isActive();
		else
			return false;
	}

	@Override
	public void mouseClicked(MouseEvent e)
	{
	}

	@Override
	public void mouseDragged(MouseEvent arg0)
	{
		if (isDrag == true)
		{
			Point containerLoc = getView().getParentLocationOnScreen();
			Point objectLoc = getView().getLocationOnScreen();

			Point delta = new Point(arg0.getXOnScreen() - previousPoint.x, arg0.getYOnScreen() - previousPoint.y);

			getView().setBounds(objectLoc.x - containerLoc.x + delta.x, objectLoc.y - containerLoc.y + delta.y, arg0.getComponent().getWidth(), arg0.getComponent().getHeight());
			getView().repaint();
			previousPoint = arg0.getLocationOnScreen();
		}
	}

	@Override
	public void mouseEntered(MouseEvent e)
	{
	}

	@Override
	public void mouseExited(MouseEvent e)
	{
	}

	@Override
	public void mouseMoved(MouseEvent e)
	{
	}

	@Override
	public void mousePressed(MouseEvent e)
	{
		if (e.getButton() == MouseEvent.BUTTON1)
		{
			isDrag = true;
			previousPoint = e.getLocationOnScreen();
		}
		else if (e.getButton() == MouseEvent.BUTTON3)
		{
			getView().showContextMenu(e.getComponent(), e.getX(), e.getY());
		}
	}

	@Override
	public void mouseReleased(MouseEvent e)
	{
		if (e.getButton() == MouseEvent.BUTTON1)
		{
			isDrag = false;
		}
	}

	public void registerCBRD(CBRDModel model, ProcessHandler handler)
	{
		cbrdModel = model;
		cbrdProcessHandler = handler;
		getView().changeMenusForCBRD(true);
	}

	public void registerMidas(MidasModel model, ProcessHandler handler)
	{
		midasModel = model;
		midasProcessHandler = handler;
		sensorsServer = new ProcessingAlgorithmServer();
		sensorsServer.init(midasModel.getIpAddress());
		sensorsServer.start();
		getView().changeMenusForMidas(true);
	}

	public void removeApplications()
	{
		for (ProcessHandler handler : applications)
		{
			handler.terminate();
		}
	}

	public void removeSensor(ASensor selectedSensor)
	{
		if (sensors.contains(selectedSensor))
			sensors.remove(selectedSensor);

		sensorsServer.deregisterSensor(selectedSensor);

		selectedSensor.terminate();

		getView().drawSensors();
	}

	public void terminate()
	{
		if (midasModel != null)
			getView().freeIfaceByName(midasModel.getInterfaceName());

		if (midasProcessHandler != null)
			midasProcessHandler.terminate();

		if (cbrdProcessHandler != null)
			cbrdProcessHandler.terminate();

		for (ProcessHandler application : applications)
			application.terminate();

		for (ASensor sensor : sensors)
			sensor.terminate();

		if (sensorsServer != null)
			sensorsServer.terminate();
	}

	public void terminateCBRD()
	{
		if (cbrdProcessHandler != null)
			cbrdProcessHandler.terminate();
	}
}
